package ffte.native

import breeze.math.Complex
import ffte.algorithm.FFTGen.ffter

/**
 * Native FFT implementation wrapper
 *
 * This class provides a native software implementation of FFT algorithms
 * using the generated FFT structure. It serves as a reference implementation
 * for validating hardware designs and providing accurate software baseline
 * for comparison.
 *
 * Architecture:
 * - Input buffer management with configurable parallelism (S)
 * - Input permutation using load table for algorithm-specific ordering
 * - Recursive FFT computation using Native method generator
 * - Output permutation using store table for final result ordering
 *
 * Data Flow:
 * 1. Input permutation: reorder input according to algorithm requirements
 * 2. FFT computation: apply generated FFT structure recursively
 * 3. Output permutation: reorder results for natural output ordering
 *
 * @param p Generated FFT structure with algorithm-specific parameters
 * @param S Parallelism factor for FFT computation
 */
class NFFT(p:ffter[Native],val S:Int) extends NativeFFT {

    /** Input buffer for permuted data */
    val inBuf  = new Array[Complex](p.rN)

    /** Native FFT method generator with specified parallelism */
    val g      = new Native(S)

    /** Generated FFT computation structure */
    val fft    = g(p.fft,"top")

    /**
     * Perform FFT transformation
     *
     * Applies the complete FFT algorithm including input permutation,
     * recursive computation, and output reordering.
     *
     * @param x Input complex array
     * @return FFT-transformed complex array
     */
    def transform(x: Array[Complex]): Array[Complex] = {
        // Input permutation: reorder according to load table
        for(i <- 0 until p.rN) {
            inBuf(i) = x(p.load_tab(i))
        }

        // Recursive FFT computation
        val tf = fft.transform(inBuf)

        // Output permutation: reorder according to store table
        val r  = new Array[Complex](p.rN)
        for(i <- 0 until p.rN) {
            r(p.store_tab(i)) = tf(i)
        }
        r
    }
}

/**
 * Native IFFT implementation wrapper
 *
 * This class provides a native software implementation of Inverse FFT
 * algorithms. It implements the IFFT using FFT with complex conjugation
 * preprocessing and postprocessing.
 *
 * Mathematical Foundation:
 * IFFT can be computed using FFT with conjugation:
 * X[k] = FFT(x*[n])*
 * where * denotes complex conjugation and proper scaling
 *
 * Implementation Strategy:
 * 1. Input conjugation: swap real and imaginary parts
 * 2. FFT computation on conjugated input
 * 3. Output conjugation: swap real and imaginary parts back
 *
 * @param p Generated FFT structure with algorithm-specific parameters
 * @param S Parallelism factor for FFT computation
 */
class NIFFT(p:ffter[Native],val S:Int) extends NativeFFT {

    /** Input buffer for permuted and conjugated data */
    val inBuf  = new Array[Complex](p.rN)

    /** Native FFT method generator with specified parallelism */
    val g      = new Native(S)

    /** Generated FFT computation structure */
    val fft    = g(p.fft,"top")

    /**
     * Complex number conjugation by swapping components
     *
     * Performs complex conjugation by swapping real and imaginary parts.
     * This is equivalent to multiplication by -j for 90-degree rotation.
     *
     * @param x Input complex number
     * @return Conjugated complex number (swapped components)
     */
    def swap(x:Complex) : Complex = {
        Complex(x.im,x.re)
    }

    /**
     * Perform IFFT transformation
     *
     * Implements IFFT using FFT with conjugation preprocessing and
     * postprocessing. Applies the complete algorithm including input
     * conjugation, permutation, FFT computation, and output processing.
     *
     * @param x Input complex array for inverse transform
     * @return IFFT-transformed complex array
     */
    def transform(x: Array[Complex]): Array[Complex] = {
        // Input conjugation and permutation
        for(i <- 0 until p.rN) {
            inBuf(i) = swap(x(p.load_tab(i)))
        }

        // FFT computation on conjugated input
        val tf = fft.transform(inBuf)

        // Output conjugation and permutation
        val r  = new Array[Complex](p.rN)
        for(i <- 0 until p.rN) {
            r(p.store_tab(i)) = swap(tf(i))
        }
        r
    }
}